package com.surfilter.platform.base.util;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import net.sf.ezmorph.object.DateMorpher;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;
import net.sf.json.processors.JsonValueProcessor;
import net.sf.json.util.JSONUtils;

import org.apache.log4j.Logger;

import com.surfilter.modules.syslog.model.SyslogQueryCondition;
import com.surfilter.platform.base.exception.ExceptionBase;
import com.surfilter.platform.base.exception.SystemException;

public class ObjectUtil {

	private static Logger logger = Logger.getLogger(ExceptionBase.LOG_SYSTEM);
	
	private static String[] formats = {"yyyy-MM-dd","yyyy-MM-dd HH:mm:ss"};

	static {
		JSONUtils.getMorpherRegistry().registerMorpher(
				new DateMorpher(formats));
	}

	public static Map objectToMap(Object object) {
		try {
			if (object == null)
				return null;
			Class cls = object.getClass();
			if (Map.class.isAssignableFrom(cls)) {
				return (Map) object;
			} else {
				return objectToMapByCls(object, object.getClass());
			}
		} catch (Exception e) {
			return null;
		}
	}

	public static Map objectToMapByCls(Object object, Class cls) {
		try {
			Map<String, Object> map = new HashMap<String, Object>();
			Field[] fields = cls.getDeclaredFields();
			for (Field field : fields) {
				Method getterMethod = getGetterMethod(cls, field);
				if (getterMethod != null) {
					map.put(field.getName(), getterMethod.invoke(object, null));
				}
			}
			Class scls = cls.getSuperclass();
			if (scls != null && !scls.equals(java.lang.Object.class)) {
				map.putAll(objectToMapByCls(object, scls));
			}
			return map;
		} catch (Exception e) {
			return null;
		}
	}

	public static boolean isBasicClass(Class type) {
		return type.equals(String.class) || type.equals(int.class)
				|| type.equals(short.class) || type.equals(long.class)
				|| type.equals(double.class) || type.equals(boolean.class)
				|| type.equals(float.class)
				|| Date.class.isAssignableFrom(type)
				|| type.equals(String.class) || type.equals(Integer.class)
				|| type.equals(Short.class) || type.equals(Long.class)
				|| type.equals(Double.class) || type.equals(Boolean.class)
				|| type.equals(Float.class);
	}

	public static boolean isCollectionClass(Class type) {
		return Collection.class.isAssignableFrom(type);
	}

	public static boolean isArrayClass(Class type) {
		return type.isArray();
	}

	public static Object getBasicObjectValue(Class type, String value) {
		if (value == null)
			return null;
		Object retValue = value;
		if (type.equals(int.class)) {
			if (value == null || value.trim().length() == 0)
				retValue = 0;
			else {
				retValue = Integer.parseInt(value);
			}
		} else if (type.equals(short.class)) {
			if (value == null || value.trim().length() == 0)
				retValue = 0;
			else {
				retValue = Short.parseShort(value);
			}
		} else if (type.equals(double.class)) {
			if (value == null || value.trim().length() == 0)
				retValue = 0;
			else {
				retValue = Double.parseDouble(value);
			}
		} else if (type.equals(long.class)) {
			if (value == null || value.trim().length() == 0)
				retValue = 0;
			else {
				retValue = Long.parseLong(value);
			}
		} else if (type.equals(boolean.class)) {
			if (value == null || value.trim().length() == 0)
				retValue = false;
			else {
				retValue = Boolean.parseBoolean(value);
			}
		} else if (type.equals(float.class)) {
			if (value == null || value.trim().length() == 0)
				retValue = 0f;
			else {
				retValue = Float.parseFloat(value);
			}
		} else if (type.equals(Integer.class)) {
			if (value == null || value.trim().length() == 0)
				retValue = null;
			else {
				retValue = Integer.valueOf(value);
			}
		} else if (type.equals(Short.class)) {
			if (value == null || value.trim().length() == 0)
				retValue = null;
			else {
				retValue = Short.valueOf(value);
			}
		} else if (type.equals(Double.class)) {
			if (value == null || value.trim().length() == 0)
				retValue = null;
			else {
				retValue = Double.valueOf(value);
			}
		} else if (type.equals(Long.class)) {
			if (value == null || value.trim().length() == 0)
				retValue = null;
			else {
				retValue = Long.valueOf(value);
			}
		} else if (type.equals(Boolean.class)) {
			if (value == null || value.trim().length() == 0)
				retValue = null;
			else {
				retValue = Boolean.valueOf(value);
			}
		} else if (type.equals(Float.class)) {
			if (value == null || value.trim().length() == 0)
				retValue = null;
			else {
				retValue = Float.valueOf(value);
			}
		} else if (type.equals(Date.class)) {
			if (value == null || value.trim().length() == 0)
				retValue = null;
			else {
				retValue = formatParamDate(value);
			}
		}
		return retValue;
	}

	public static Object getObjectBeanFromJsonObjectString(Class beanClass,
			String jsonObjectStr) {
		try {
			if (jsonObjectStr != null) {
				JSONObject jsonObject = JSONObject.fromObject(jsonObjectStr);
				if (jsonObject != null) {
					Object object = JSONObject.toBean(jsonObject, beanClass);
					return object;
				}
			}
		} catch (Exception e) {
			new SystemException(e);
		}
		return null;
	}

	public static Object getObjectArrayFromJsonArrayString(Class beanClass,
			String jsonArrayStr) {
		try {
			if (jsonArrayStr != null) {
				JSONArray jsonArray = JSONArray.fromObject(jsonArrayStr);
				if (jsonArray != null) {
					Object objs = JSONArray.toArray(jsonArray, beanClass);
					return objs;
				}
			}
		} catch (Exception e) {
			new SystemException(e);
		}
		return null;
	}

	public static Object getObjectCollectionFromJsonArrayString(
			Class beanClass, String jsonArrayStr, Class retClass) {
		try {
			Collection col = null;
			if (jsonArrayStr != null) {
				JSONArray jsonArray = JSONArray.fromObject(jsonArrayStr);
				if (jsonArray != null) {
					col = JSONArray.toCollection(jsonArray, beanClass);
					return col;
				}
			}
			if (col != null && Collection.class.isAssignableFrom(retClass)) {
				if (retClass.isInterface()) {
					if (List.class.isAssignableFrom(retClass)) {
						ArrayList list = new ArrayList(col);
						return list;
					} else if (Set.class.isAssignableFrom(retClass)) {
						HashSet set = new HashSet(col);
						return set;
					} else {
						return col;
					}
				} else {
					Collection robj = (Collection) retClass.newInstance();
					Collections.addAll(robj, col);
					return robj;
				}

			}
		} catch (Exception e) {
			new SystemException(e);
		}
		return null;
	}

	public static Object transferStringArrayToObjectArray(Class componentType,
			String[] srcArrays) {
		if (srcArrays != null && srcArrays.length > 0) {
			int length = srcArrays.length;
			Object objects = Array.newInstance(componentType, length);
			for (int i = 0; i < length; i++) {
				try {
					String objectValue = srcArrays[i];
					Object value = null;
					if (objectValue.startsWith("{")
							&& objectValue.endsWith("}")) {
						value = getObjectBeanFromJsonObjectString(
								componentType, objectValue);
					} else {
						value = getBasicObjectValue(componentType, objectValue);
					}
					Array.set(objects, i, value);
				} catch (Exception e) {
					new SystemException(e);
					continue;
				}
			}
			return objects;
		}
		return null;
	}

	public static Object transferStringArrayToObjectCollection(
			Class componentType, String[] stringArray, Class retClass) {
		try {
			ArrayList col = new ArrayList();
			int length;
			if (stringArray != null && (length = stringArray.length) > 0) {
				for (int i = 0; i < length; i++) {
					String objectValue = stringArray[i];
					Object value = null;
					if (objectValue.startsWith("{")
							&& objectValue.endsWith("}")) {
						value = getObjectBeanFromJsonObjectString(
								componentType, objectValue);
					} else {
						value = getBasicObjectValue(componentType, objectValue);
					}
					col.add(value);
				}
			}
			if (col != null && col.size() > 0
					&& Collection.class.isAssignableFrom(retClass)) {
				if (retClass.isInterface()) {
					if (List.class.isAssignableFrom(retClass)) {
						return col;
					} else if (Set.class.isAssignableFrom(retClass)) {
						HashSet set = new HashSet(col);
						return set;
					} else {
						return col;
					}
				} else {
					if (ArrayList.class.equals(retClass)) {
						return col;
					} else {
						Collection robj = (Collection) retClass.newInstance();
						Collections.addAll(robj, col);
						return robj;
					}
				}

			}
		} catch (Exception e) {
			new SystemException(e);
		}
		return null;
	}

	public static void setObjectValuesFromRequest(Object typeObject,
			HttpServletRequest params, Class cls) {
		Field[] fields = cls.getDeclaredFields();
		for (Field field : fields) {
			try {
				String fieldName = field.getName();
				Class typeClass = field.getType();
				Method setter = getSetterMethod(cls, field);
				if (setter == null) {
					continue;
				}
				String valueObject = params.getParameter(fieldName);
				String[] valueObjectArr = params.getParameterValues(fieldName);
				if (valueObject == null
						&& (valueObjectArr == null || valueObjectArr.length == 0)) {
					continue;
				}
				if (ObjectUtil.isBasicClass(typeClass)) {
					Object value = ObjectUtil.getBasicObjectValue(typeClass,
							valueObject);
					setter.invoke(typeObject, value);
				}

			} catch (Exception a) {
				logger.error("Get Params Object Error", a);
				continue;
			}
		}
		Class scls = cls.getSuperclass();
		if (scls != null && !scls.equals(java.lang.Object.class)) {
			setObjectValuesFromRequest(typeObject, params, scls);
		}
	}

	public static Object getObjectBeanFromRequest(Object typeObject,
			HttpServletRequest params) throws InstantiationException,
			IllegalAccessException {
		Class cls = typeObject.getClass();
		setObjectValuesFromRequest(typeObject, params, cls);
		return typeObject;
	}

	public static Date formatParamDate(String dateStr) {
		try {
			String regex = getFormatRegex(dateStr);
			SimpleDateFormat format = new SimpleDateFormat(regex);
			Date t = format.parse(dateStr);
			return t;
		} catch (Exception e) {
			throw new SystemException("FormatParamDate Error", e);
		}
	}

	private static String getFormatRegex(String dateStr) {
		dateStr = dateStr.trim();
		String splitDate = "-";
		String splitTime = ":";

		if (dateStr.indexOf("/") > 0)
			splitDate = "/";
		StringBuilder builder = new StringBuilder("yyyy" + splitDate + "MM"
				+ splitDate + "dd");
		if (dateStr.split(" ").length == 2) {
			builder.append(" HH");
		}
		int timeLength = dateStr.split(splitTime).length;
		if (timeLength == 2) {
			builder.append(":mm");
		} else if (timeLength == 3) {
			builder.append(":mm:ss");
		}
		return builder.toString();
	}

	private static Method getGetterMethod(Class cls, Field field) {
		try {
			String prefix = boolean.class.equals(field.getType()) ? "is"
					: "get";
			String getterName = getMethodNameByPrefixAndFieldName(
					field.getName(), prefix);
			Method method = cls.getDeclaredMethod(getterName, new Class[] {});
			int modifiers = method.getModifiers();
			if (Modifier.isProtected(modifiers) || Modifier.isPublic(modifiers)) {
				return method;
			}
		} catch (Exception e) {
		}
		return null;
	}

	public static Method getSetterMethod(Class cls, Field field) {
		try {
			String setterName = getMethodNameByPrefixAndFieldName(
					field.getName(), "set");
			Method method = cls.getDeclaredMethod(setterName,
					new Class[] { field.getType() });
			int modifiers = method.getModifiers();
			if (Modifier.isProtected(modifiers) || Modifier.isPublic(modifiers)) {
				return method;
			}
		} catch (Exception e) {
		}
		return null;
	}

	private static String getMethodNameByPrefixAndFieldName(String fieldName,
			String prefix) {
		return prefix + fieldName.substring(0, 1).toUpperCase()
				+ fieldName.substring(1);
	}

}
